Java基础知识(八)
对象比较
1.数字比较用==
,字符串比较用equals(String str)
。
要进行对象比较,必须对对象中所有属性的值进行比较。
范例:对象比较的基本方式
class Book {
private String title;
private double price;
public Book(String title, double price) {
this.title = title;
this.price = price;
}
//省略无参构造方法和setter方法
public String getTitle() {
return this.title;
}
public double getPrice() {
return this.price;
}
}
public class Demo {
public static void main(String[] args) {
Book bkA = new Book("Java开发", 79.5);
Book bkB = new Book("JSP", 45.6);
if (bkA.getTitle().equals(bkB.getTitle())
&& bkA.getPrice() == bkB.getPrice()) {
System.out.println("bkA和bkB是同一个对象!");
} else {
System.out.println("bkA和bkB是不同对象!");
}
}
}
上述程序存在问题:主方法相当于客户端,客户端的程序逻辑应该越简单越好。所以对象比较应该由对象自己完成,即对象所对应的类应该提供对象比较的方法。
附:类的属性使用private封装,那么在类的外部就不能通过对象直接调用属性
class Info{
private String msg = "Hello";
public void print(){
System.out.println("msg = " + this.msg);
}
}
public class Demo {
public static void main(String[] args) {
Info x = new Info();
x.msg = "sss"; // 报错,无法访问private属性
x.print();
}
}
附:将一个对象作为参数传回类的方法中,相当于取消封装,使得对象可以直接访问属性。
class Info {
private String msg = "Hello";
public void print() {
System.out.println("msg = " + this.msg);
}
public void fun(Info temp) {
// 在类的内部直接利用对象访问私有属性
temp.msg = "修改内容";
}
}
public class Demo {
public static void main(String[] args) {
Info x = new Info();
x.fun(x);
x.print(); // msg = 修改内容
}
}
附:一个类接收本类对象形式的代码在对象比较时很常见。
class Book {
private String title;
private double price;
public Book(String title, double price) {
this.title = title;
this.price = price;
}
//省略无参构造方法和setter方法
public String getTitle() {
return this.title;
}
public double getPrice() {
return this.price;
}
// 类接收自身对象,对象可以直接访问属性,不需要getter方法
// compare()有两个功能:一带回了要比较的信息;二方便属性访问
public boolean compare(Book book) {
if (book == null) { // 要比较的对象为空
return false; // 没必要比较
}
if (this == book) { // 内存地址相同
return true; //避免具体比较,节约时间
}
// 执行“bkA.equals(bkB)”时,有两个对象:
// 一个为当前对象this(调用方法的对象,即bkA)
// 一个为传递对象book(引用传递,即bkB)
if (this.title.equals(book.title)
&& this.price == book.price) {
return true;
} else {
return false;
}
}
}
public class Demo {
public static void main(String[] args) {
Book bkA = new Book("Java开发", 79.5);
Book bkB = new Book("JSP", 45.6);
if (bkA.compare(bkB)) {
System.out.println("bkA和bkB是同一个对象!");
} else {
System.out.println("bkA和bkB是不同对象!");
}
}
}
总结
(1)对象比较的方法必须定义在类中;
(2)对象比较时一定要判断是否为null
,内存地址是否相同,属性是否相同。
关键字static
static 定义属性
问题引出:
class Book {
private String title;
private double price;
// 为操作方便,暂不封装
String pub = "清华大学出版社";
public Book(String title, double price) {
this.title = title;
this.price = price;
}
public String getInfo(){
return "书名:" + this.title + ",价格:" + this.price + ",出版社:" + this.pub;
}
}
public class Demo {
public static void main(String[] args) {
Book bkA = new Book("Java开发", 79.5);
Book bkB = new Book("JSP", 45.6);
System.out.println(bkA.getInfo()); // 清华大学出版社
System.out.println(bkB.getInfo()); // 清华大学出版社
bkB.pub = "北京大学出版社";
System.out.println(bkA.getInfo()); // 清华大学出版社
System.out.println(bkB.getInfo()); // 北京大学出版社
}
}
对上述代码进行内存分析:
通过内存分析,发现属性重复:每个对象各自占有相同的属性值。假如有1000个该对象,要修改所有对象的pub属性,就需要分别进行修改。因此如果将pub属性定为普通属性,那每个堆内存都保存有各自的pub值。
1.但所有对象的pub值都一样,应将其定为一个共享的属性,即所有对象都指向同一块pub属性。可以利用static
定义共享属性。
class Book {
private String title;
private double price;
// 为操作方便,暂不封装
static String pub = "清华大学出版社";
public Book(String title, double price) {
this.title = title;
this.price = price;
}
public String getInfo(){
return "书名:" + this.title + ",价格:" + this.price + ",出版社:" + this.pub;
}
}
public class Demo {
public static void main(String[] args) {
Book bkA = new Book("Java开发", 79.5);
Book bkB = new Book("JSP", 45.6);
System.out.println(bkA.getInfo()); // 清华大学出版社
System.out.println(bkB.getInfo()); // 清华大学出版社
bkB.pub = "北京大学出版社";
System.out.println(bkA.getInfo()); // 北京大学出版社
System.out.println(bkB.getInfo()); // 北京大学出版社
}
}
使用static
定义属性后,只要有一个对象修改属性值,那么所有对象的该属性值都会改变,内存分析如下:
2. static
定义的属性与普通属性区别在于保存数据的内存区域不同。
static
定义的是公共属性,任由某个对象直接修改属性值是不合理的,应该由所有对象的代表进行属性访问,即用类访问。因此static
定义的属性,可直接用类名调用:Book.pub = "北京大学出版社";
3. static
属性与普通属性的区别在于:普通属性必须由实例化的对象调用,而在没有实例化对象的情况下,static属性依然可以被调用。
public class Demo {
public static void main(String[] args) {
// 没有实例化对象的情况下,输出pub的内容
System.out.println(Book.pub);
}
}
由结果可知:static
虽然定义在类中,但不受对象控制,是独立于类存在的。
4. 何时使用static定义属性
编写类时,static
不是首选修饰符,当需要描述共享信息时,才使用static,方便集体修改,不用重复开辟内存空间。
static 定义方法
1.static
定义的方法也可以直接被类名调用
class Book {
private String title;
private double price;
// 为操作方便,暂不封装
private static String pub = "清华大学出版社";
public Book(String title, double price) {
this.title = title;
this.price = price;
}
public static void setPub(String p){
pub = p;
}
public String getInfo(){
return "书名:" + this.title + ",价格:" + this.price + ",出版社:" + this.pub;
}
}
public class Demo {
public static void main(String[] args) {
// 没有实例化对象的情况下,调用方法
Book.setPub("北京大学出版社");
Book bkA = new Book("Java开发", 79.5);
System.out.println(bkA.getInfo()); // 北京大学出版社
}
}
上述代码存在问题:类中有两种方法,static方法和普通方法,两种方法间的访问受到限制。
(1)static方法不能直接使用非static属性或方法,只能调用static属性或方法。
public static void setPub(String p){
pub = p;
title = "sss"; // 报错,无法引用非静态变量
getInfo(); // 报错,无法引用非静态方法
System.out.println(this); // 报错,无法引用非静态变量
}
(2)普通方法可以使用static属性或方法
public String getInfo(){
setPub(""); // 不报错
return ",出版社:" + this.pub; // 不报错
}
出现上述限制的原因:
|- 普通属性和方法必须在对象实例化后分配了堆内存空间,才可以使用;
|- static定义的方法和属性,不受实例化对象控制,可在没有实例化对象情况下访问。
2.一个方法定义在主类中,并由主方法直接调用,该方法定义格式如下:
public static 返回值类型 方法名(参数类型 参数, 参数类型 参数,...) {
方法体;
[return [返回值] ;] // []中内容可写可不写
}
一个方法定义在类中,由对象直接调用,其语法格式如下:
public 返回值类型 方法名(参数类型 参数, 参数类型 参数,...) {
方法体;
[return [返回值] ;] // []中内容可写可不写
}
观察代码:
public class Demo {
public static void main(String[] args) {
fun();
}
public static void fun() {
System.out.println("Hello World !");
}
}
没有static定义的fun()必须通过对象调用,主方法要使用fun()必须实例化对象
public class Demo {
public static void main(String[] args) {
// 产生对象,再利用对象调用非static方法
new Demo().fun();
}
public void fun() {
System.out.println("Hello World !");
}
}
- 定义类中方法时,
static
不是首选修饰符,因为每个对象可以利用自己的属性实现方法的不同调用。
class Flag {
private boolean flag;
public Flag(boolean flag) {
this.flag = flag;
}
public void fun() {
if (this.flag) {
System.out.println("可以操作");
} else {
System.out.println("不可以操作");
}
}
}
public class Demo {
public static void main(String[] args) {
Flag fA = new Flag(true);
Flag fB = new Flag(false);
fA.fun();
fB.fun();
}
}
当一个类中没有属性,只有方法时,建议将所有方法定义为static方法。这样就不用每次调用时都需要有实例化对象。
class MyMath {
public static int add(int x, int y) {
return x + y;
}
}
public class Demo {
public static void main(String[] args) {
System.out.println(MyMath.add(10, 20));
}
}
主方法
1.主方法的组成:
组成 | 作用 |
---|---|
public | 主方法是程序的开始,所以主方法必须是可见、public(公共的)的 |
static | 证明此方法可直接由类名调用 |
void | 主方法是程序的开始,因此不能回头,执行完为止,所以不能有返回值 |
main | 系统规定好的方法名,不能修改 |
String [] args | 指的是程序运行时传递的参数 |
范例:对主方法传入参数
public class Demo {
public static void main(String[] args) {
for (int x = 0; x < args.length ; x++) {
System.out.println(args[x]); // 未输出参数,为空
}
}
}
多个参数时,必须使用空格分割。cmd执行的是java Demo 1 3 4 6
输出为:1 3 4 6
如果参数本身带有空格,需用""
描述
cmd执行的是java Demo "Hello world" "Hello Java"
static应用案例
已知:
(1)多个对象,都使用同一个static属性;
(2)static定义方法可以避免实例化对象调用方法的限制。
1.实现对实例化对象个数的统计
要求:每实例化一个对象,就输出"这是第x个实例化对象"
思路:每次实例化对象,就会调用构造方法,因此可在构造方法中增加一个统计数据的操作,每当新对象产生,该属性值就自增加一。
class Book {
private static int num = 0;
public Book() {
num++;
System.out.println("这是第" + num + "个实例化对象");
}
}
public class Demo {
public static void main(String[] args) {
new Book();
new Book();
new Book();
}
}
2.实现属性的自动设置
要求:类中有一个无参构造方法,一个有参构造方法,有参构造方法的功能是传递title值。不论调用的哪个构造方法,均可为title赋值,且属性值尽量不重复。
class Book {
private String title;
private static int num = 0;
public Book() {
this("Title:No." + num++);
}
public Book(String title){
this.title = title;
}
public String getTitle(){
return this.title;
}
}
public class Demo {
public static void main(String[] args) {
System.out.println(new Book("Java开发").getTitle()); // Java开发
System.out.println(new Book().getTitle()); // Title:No.0
System.out.println(new Book().getTitle()); // Title:No.1
}
}
总结
(1)类定义属性或方法首时选不是static属性或方法;
(2)static属性或方法可直接用类名调用;
(3)static属性保存在全局数据区。
(4)内存区有四种: 栈内存(对象的地址),堆内存(普通属性),全局数据区(static属性),全局代码区(所有的方法)
This blog is under a CC BY-NC-SA 3.0 Unported License
本文链接:http://yov.oschina.io/article/Java/Java Base/Java基础知识(八)/